package __Colly

import (
	"fmt"
	"github.com/gocolly/colly"
	"github.com/gocolly/colly/debug"
	"net"
	"net/http"
	"regexp"
	"time"
)

// @author    : 逆向与爬虫的故事
// @time      : 2022/10/6 13:24
// -------------------------------------------

func main() {
	mUrl := "http://www.ifeng.com/"
	//colly的主体是Collector对象，管理网络通信和负责在作业运行时执行附加的回掉函数
	c := colly.NewCollector(
		// 开启DEBUG
		colly.Debugger(&debug.LogDebugger{}),

		//爬取深度
		colly.MaxDepth(1),

		// 是否开启异步
		colly.Async(true),
		// 跨域设置
		colly.AllowedDomains("www.ifeng.com"),
		// 允许重复抓取
		colly.AllowURLRevisit(),
		// url设置
		colly.URLFilters(
			regexp.MustCompile(".*"),
		),
		// 设置UA
		colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"),
	)
	c.Limit(&colly.LimitRule{
		Parallelism: 5,               // 并发设置
		Delay:       time.Second * 3, // 下载延时
		RandomDelay: time.Second * 5, // 随机延时
	})

	// 代理、连接数、上下文机制、超时等配置
	c.WithTransport(&http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second, // 超时时间
			KeepAlive: 30 * time.Second, // keepAlive 超时时间
		}).DialContext,
		MaxIdleConns:          100,              // 最大空闲连接数
		IdleConnTimeout:       90 * time.Second, // 空闲连接超时
		TLSHandshakeTimeout:   10 * time.Second, // TLS 握手超时
		ExpectContinueTimeout: 1 * time.Second,
	})
	//发送请求之前的执行函数
	c.OnRequest(func(r *colly.Request) {
		fmt.Println("这里是发送之前执行的函数")
	})
	//发送请求错误被回调
	c.OnError(func(_ *colly.Response, err error) {
		fmt.Print(err)
	})
	//响应请求之后被回调
	c.OnResponse(func(r *colly.Response) {
		fmt.Println("Response body length：", len(r.Body))
	})
	//response之后会调用该函数，分析页面数据
	c.OnHTML("p a", func(e *colly.HTMLElement) {
		fmt.Println(e.Text)
	})
	//在OnHTML之后被调用
	c.OnScraped(func(r *colly.Response) {
		fmt.Println("Finished", r.Request.URL)
	})
	//这里是执行访问url
	c.Visit(mUrl)
}
